package com.koelo.kiss.re.spring;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PropertyTemplateConfigurer 
	implements ApplicationContextAware, InitializingBean {

	private Map<String, List<Object>> beans;
	private ApplicationContext applicationContext;
	private PropertyReader propertyReader;
	private List<String> templates;
	private Set<String> names;
	
	public PropertyTemplateConfigurer() {
		
		this.beans = new HashMap<String, List<Object>>();
		this.names = new HashSet<String>();
	}
	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) 
		throws BeansException {
		
		this.applicationContext = applicationContext;
	}

	public ApplicationContext getApplicationCotext() {
		
		return this.applicationContext;
	}
	
	public void setPropertyReader(PropertyReader propertyReader) {
		
		this.propertyReader = propertyReader;
	}
	
	public PropertyReader getPropertyReader() {
		
		return this.propertyReader;
	}
	
	public void setTemplates(List<String> templates) {
		
		this.templates = templates;
	}
	
	public List<String> getTemplates() {
		
		return this.templates;
	}
	
	public void setNames(Set<String> names) {
		
		this.names = names;
	}
	
	public Set<String> getNames() {
		
		return this.names;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		
		if (getTemplates() == null) {
			throw new IllegalArgumentException("Argument templates not found. Use property templates to set it.");
		}
		if (getNames() == null) {
			throw new IllegalArgumentException("Argument names not found. Use property names to set it.");
		}
		if (getPropertyReader() != null) {
			Set<Properties> properties = getPropertyReader().getProperties();
			for (Properties props: properties) {
				if (this.names.contains(((NamedProperties) props).getName())) {
					ClassPathXmlApplicationContext context = createApplicationContext(props);
					context.refresh();
					String name = ((NamedProperties) props).getName();
					List<Object> beans = this.beans.get(name);
					beans = beans == null ? new ArrayList<Object>() : beans;
					beans.add(context.getBean(name));
					this.beans.put(name, beans);
				} else {
					ClassPathXmlApplicationContext context = createApplicationContext(props);
					context.refresh();
				}
			}
		} else {
			ClassPathXmlApplicationContext context = createApplicationContext();
			context.refresh();
			for (String name: getNames()) {
				List<Object> beans = this.beans.get(name);
				if (beans == null) {
					beans = new ArrayList<Object>();
				}
				beans.add(context.getBean(name));
				this.beans.put(name, beans);
			}
		}
	}
	
	private ClassPathXmlApplicationContext createApplicationContext() {

		String[] locations = new String[getTemplates().size()];
		getTemplates().toArray(locations);
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(getApplicationCotext());
		context.setConfigLocations(locations);
		return context;
	}
	
	private ClassPathXmlApplicationContext createApplicationContext(Properties properties) {

		ClassPathXmlApplicationContext context = createApplicationContext();
		PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
		configurer.setProperties(properties);
		context.addBeanFactoryPostProcessor(configurer);
		return context;
	}
	
	public List<Object> getBeans(String name) {
		
		return this.beans.get(name);
	}
	
	public Object getBean(String name) {

		Object bean = null;
		List<Object> beans = getBeans(name);
		if (beans.size() > 0) {
			bean = beans.get(0);
		}
		return bean;
	}

	
	public static void main(String args[]) {

		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/kiss-server-context.xml");
		applicationContext.start();
    	while (true) {
        	try {
        		Thread.sleep(2000);
        	} catch (InterruptedException ex) {
        		
        	}
    	}
	}
}
